package jhunter.service;

import java.lang.reflect.Method;

import jhunter.annotation.WithoutTransaction;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

public class ServiceInterceptor implements MethodInterceptor {

	private boolean hasMatchMethod(Method method) {
		boolean has = false;
		Method[] methods = BaseService.class.getMethods();
		for (Method method2 : methods) {
			if (method2.equals(method)) {
				return true;
			}
		}
		return has;
	}

	@Override
	public Object intercept(final Object obj, Method method,
			final Object[] args, final MethodProxy proxy) throws Throwable {
		// Transactional tran = method.getAnnotation(Transactional.class);
		boolean needTransaction = true;
		if (!(obj instanceof Service) || method.getName().startsWith("set")
				|| method.getAnnotation(WithoutTransaction.class) != null || hasMatchMethod(method)) {
			needTransaction = false;
		}
		if (needTransaction) {
			BaseService service = (BaseService) obj;
			TransactionTemplate t = service.getTransactionTemplate();
			String methodName = method.getName();
			if (methodName.startsWith("get")) {
				t.setReadOnly(true);
			}
			Class<?> re = method.getReturnType();
			if (re.equals(Void.class)) {
				return t.execute(new TransactionCallbackWithoutResult() {
					@Override
					protected void doInTransactionWithoutResult(
							TransactionStatus status) {
						try {
							proxy.invokeSuper(obj, args);
						} catch (Throwable e) {
							e.printStackTrace();
							throw new RuntimeException(e);
						}
					}
				});
			} else {
				return t.execute(new TransactionCallback<Object>() {
					@Override
					public Object doInTransaction(TransactionStatus status) {
						try {
							return proxy.invokeSuper(obj, args);
						} catch (Throwable e) {
							e.printStackTrace();
							throw new RuntimeException(e);
						}
					}

				});
			}

		} else {
			return proxy.invokeSuper(obj, args);
		}
	}
}
